package com.stylefeng.guns.core.shiro.factory;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.stylefeng.guns.core.common.constant.factory.ConstantFactory;
import com.stylefeng.guns.core.common.constant.state.ManagerStatus;
import com.stylefeng.guns.core.shiro.ShiroUser;
import com.stylefeng.guns.core.util.Convert;
import com.stylefeng.guns.core.util.SpringContextHolder;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.modular.system.dao.*;
import com.stylefeng.guns.modular.system.model.*;
import org.apache.commons.collections.FastArrayList;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@DependsOn("springContextHolder")
@Transactional(readOnly = true)
public class ShiroFactroy implements IShiro {

  @Autowired private UserMapper userMapper;

  @Autowired private MenuMapper menuMapper;

  @Autowired private UserCwMapper userCwMapper;

  @Autowired private PostMapper postMapper;

  @Autowired private FunctionMapper functionMapper;

  @Inject private OrgcategoryFunctionMapper orgcategoryFunctionMapper;

  @Autowired private OrgMapper orgMapper;

  @Inject private SysDictMapper sysDictMapper;

  public static IShiro me() {
    return SpringContextHolder.getBean(IShiro.class);
  }

  @Override
  public User user(String account) {

    User user = userMapper.getByAccount(account);

    // 账号不存在
    if (null == user) {
      throw new CredentialsException();
    }
    // 账号被冻结
    if (user.getStatus() != ManagerStatus.OK.getCode()) {
      throw new LockedAccountException();
    }
    return user;
  }

  @Override
  public UserCw userCw(String account) {
    try {
      UserCw user = UserCw.class.newInstance();
      user.setSuLoginName(account);
      UserCw userCw = userCwMapper.selectOne(user);
      return userCw;
    } catch (InstantiationException | IllegalAccessException e) {
      e.printStackTrace();
    }
    return null;
  }

  @Override
  public ShiroUser shiroUser(User user) {
    ShiroUser shiroUser = new ShiroUser();

    shiroUser.setId(user.getId());
    shiroUser.setAccount(user.getAccount());
    shiroUser.setDeptId(user.getDeptid());
    shiroUser.setDeptName(ConstantFactory.me().getDeptName(user.getDeptid()));
    shiroUser.setName(user.getName());

    String[] roleArray = Convert.toStrArray(",",user.getRoleid());
    List<String> roleList = new ArrayList<String>();
    List<String> roleNameList = new ArrayList<String>();
    for (String roleId : roleArray) {
      roleList.add(roleId);
      roleNameList.add(ConstantFactory.me().getSingleRoleName(roleId, 0));
    }

    shiroUser.setRoleList(roleList);
    shiroUser.setRoleNames(roleNameList);

    return shiroUser;
  }

  @Override
  public ShiroUser shiroUser(UserCw user) {
    ShiroUser shiroUser = new ShiroUser();
    shiroUser.setId(user.getSuId());
    shiroUser.setAccount(user.getSuLoginName());
    shiroUser.setName(user.getSuiName());
    String[] roleArray = Convert.toStrArray(",",user.getSrId());
    List<String> roleList = new ArrayList<>();
    Integer orgId = user.getSoId();
    if (orgId != null) {
      Org org = orgMapper.selectById(orgId);
      if (org != null) {
        int pid = org.getSoPid();
        int soLevel = org.getSoLevel();
        String pids = org.getSoPids();
        String soType = org.getSoType();
        if (StrUtil.equals("1", soType)) { // 机构
          shiroUser.setSoId(user.getSoId());
          shiroUser.setDeptId(user.getSoId());
          shiroUser.setSoName(ConstantFactory.me().getOrgName(user.getSoId()));
          shiroUser.setDeptName(ConstantFactory.me().getOrgName(user.getSoId()));
        } else { // 部门 追溯直接父机构
          shiroUser.setDeptId(org.getSoId());
          shiroUser.setDeptName(ConstantFactory.me().getOrgName(org.getSoId()));
          while (true) {
            Org org_ = this.orgMapper.selectById(pid);
            if(org_!=null){
              String soType_ = org_.getSoType();
              if (StrUtil.equals("1", soType_)) {
                shiroUser.setSoId(org_.getSoId());
                shiroUser.setSoName(ConstantFactory.me().getOrgName(org_.getSoId()));
                break;
              }
                pid=org_.getSoPid();
            }
          }
        }
        int index=0;
        if (soLevel > 1) {
          index = 1;
        }else {
            shiroUser.setSoCate(org.getSoCate());
        }
        String rpid = StringUtils.split(pids,",")[index];
        Integer resultGetFirstNumber = ReUtil.getFirstNumber(rpid); // 提取匹配的数字
        if (resultGetFirstNumber != null) {
          org = orgMapper.selectById(resultGetFirstNumber);
          if (org != null) {
            shiroUser.setSoCate(org.getSoCate());
            shiroUser.setSoRId(resultGetFirstNumber);
            shiroUser.setSoRName(org.getSoName());
          }
        }
      }
    }

    // 岗位ID集
    List<Integer> postList = new ArrayList<Integer>();
    List<String> roleNameList = new ArrayList<String>();
    for (String roleId : roleArray) {
      roleList.add(roleId);
      roleNameList.add(ConstantFactory.me().getSingleRoleName(roleId, 1));
    }
    // 主岗ID
    Integer spId = user.getSpId();
    if (ToolUtil.isNotEmpty(spId)) {
      Post post = this.postMapper.selectById(user.getSpId());
      if (ToolUtil.isNotEmpty(post)) {
        shiroUser.setSpId(user.getSpId());
        shiroUser.setSpName(post.getSpName());
        postList.add(spId);
      }
    }
    // 兼职岗位ID
    if (StringUtils.isNotBlank(user.getSupId())) {
      List ids = Arrays.asList(StringUtils.split(user.getSupId(),","));
      if (!ids.isEmpty()) {
        shiroUser.setSupId(Arrays.asList(StringUtils.split(user.getSupId(),",")).parallelStream().map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList()));
        List<Post> list = this.postMapper.selectBatchIds(ids);
        List<String> nameStr =list.parallelStream().sorted(Comparator.comparing(Post::getSoId)).map(Post::getSpName).collect(Collectors.toList());
        shiroUser.setSupName(nameStr);
        postList.addAll(ids);
      }
    }
 // 角色拥有权限集合
    List<Function> functionList_R = new FastArrayList();
    if (!roleList.isEmpty()) functionList_R = functionMapper.getMenusByRoleIds(roleList, 0);
    // 岗位拥有权限集合
    List<Function> functionList_p = new FastArrayList();
    if (!postList.isEmpty()) functionList_p = functionMapper.getMenusByPosts(postList, 0);

    /**add by 张亚林 读取模板角色功能权限*/
    List<Function> functionList_M=new FastArrayList();
    if (!roleList.isEmpty()) functionList_M = functionMapper.getMenusByRoleIdsForM(roleList, 0);

    // 权限并集
    List<Function> RList= Stream.of(functionList_R,functionList_p,functionList_M).flatMap(Collection::stream).distinct().sorted(Comparator.comparing(Function::getSfId)).collect(Collectors.toList());
   // Collections.sort(RList,Comparator.comparing(Function::getSfId).thenComparing(Function::getSfLevel));
    List<String> permissions =RList.parallelStream().map(Function::getSfUrl).distinct().collect(Collectors.toList());
    shiroUser.setPermissions(permissions);
    shiroUser.setRoleList(roleList);
    shiroUser.setRoleNames(roleNameList);
    return shiroUser;
  }

  @Override
  public List<String> findPermissionsByRoleId(String roleId) {
    return menuMapper.getResUrlsByRoleId(roleId);
  }

  @Override
  public String findRoleNameByRoleId(String roleId) {
    return ConstantFactory.me().getSingleRoleTip(roleId);
  }

  @Override
  public SimpleAuthenticationInfo info(ShiroUser shiroUser, User user, String realmName) {
    String credentials = user.getPassword();

    // 密码加盐处理
    String source = user.getSalt();
    ByteSource credentialsSalt = new Md5Hash(source);
    return new SimpleAuthenticationInfo(shiroUser, credentials, credentialsSalt, realmName);
  }

  @Override
  public SimpleAuthenticationInfo info(ShiroUser shiroUser, UserCw user, String realmName) {
    String credentials = user.getSuLoginPwd();

    // 密码加盐处理
    String source = user.getSuSalt();
    ByteSource credentialsSalt = new Md5Hash(source);
    return new SimpleAuthenticationInfo(shiroUser, credentials, credentialsSalt, realmName);
  }
}
